#include "main.h"
#include "mdsh.h"

static char _current_dir[128];
static void _list(char *str)
{
    mshell_printf("\r\n");

    FRESULT res;
    DIR dir;
    FILINFO fno;

    res = f_opendir(&dir, _current_dir);
    if(res == FR_OK)
    {
        for(;;)
        {
            res = f_readdir(&dir, &fno);
            if(res != FR_OK || fno.fname[0] == 0) break;
            if(fno.fattrib & AM_DIR)
            {
                mshell_printf("%s/\r\n",fno.fname);
            }
            else
            {
                mshell_printf("%s %d\r\n",fno.fname,fno.fsize);
            }
        }
        f_closedir(&dir);
    }
}

static void _mkdir(char *str)
{
    mshell_printf("\r\n");
    char *parameter = str;
    char *ptname = NULL;
    char dirname[128];

    memset(dirname,0x00,sizeof(dirname));
    strncpy(dirname,_current_dir,sizeof(dirname));

    str = parameter;
    parameter = strchr(str,' ');
    parameter++;
    ptname = parameter;

    snprintf(dirname, sizeof(dirname), "%s/%s", _current_dir,ptname);
    FRESULT res;
    res = f_mkdir(dirname);
    if(res == FR_OK)
    {
        mshell_printf("mkdir %s\r\n",dirname);
    }
    else
    {
        mshell_printf("mkdir %s error:%d\r\n",dirname, res);
    }
}

static void _rm(char *str)
{
    mshell_printf("\r\n");
    char *parameter = str;
    char *ptname = NULL;
    char dirname[128];

    memset(dirname,0x00,sizeof(dirname));
    strncpy(dirname,_current_dir,sizeof(dirname));

    str = parameter;
    parameter = strchr(str,' ');
    parameter++;
    ptname = parameter;

    snprintf(dirname, sizeof(dirname), "%s/%s", _current_dir,ptname);
    FRESULT res;
    res = f_unlink(dirname);
    if(res == FR_OK)
    {
        mshell_printf("rm %s\r\n",dirname);
    }
    else
    {
        mshell_printf("rm %s error:%d\r\n",dirname, res);
    }
}

static void _pwd(char *str)
{
    mshell_printf("\r\n");
    mshell_printf("%s\r\n",_current_dir);
}

// 0:/sub1/sub11
static void _cd(char *str)
{
    mshell_printf("\r\n");
    char *parameter = str;
    char *ptname = NULL;

    char dirname[128];

    memset(dirname,0x00,sizeof(dirname));
    strncpy(dirname,_current_dir,sizeof(dirname));

    str = parameter;
    parameter = strchr(str,' ');
    parameter++;
    ptname = parameter;

    if(strcmp(ptname,"..") == 0)
    {
        char *ptch = strrchr(_current_dir,'/');
        *ptch = 0;
    }
    else if(*ptname == '/')
    {
        memset(_current_dir,0x00,sizeof(_current_dir));
        strncpy(_current_dir,"0:",sizeof(_current_dir));
    }
    else
    {
        snprintf(dirname, sizeof(dirname), "%s/%s", _current_dir,ptname);
        mshell_printf("dirname = %s\r\n",dirname);
        FRESULT res;
        FILINFO fno;
        res = f_stat(dirname, &fno);
        if((res == FR_OK)&&(fno.fattrib&AM_DIR))
        {
            mshell_printf("cd %s\r\n",ptname);
            strncpy(_current_dir,dirname,sizeof(_current_dir));
        }
        else
        {
            mshell_printf("cd %s error:%d\r\n",ptname,res);
        }
    }
}

static void _cat(char *str)
{
    mshell_printf("\r\n");
    char *parameter = str;
    char *ptname = NULL;
    uint32_t length = 0;
    char dirname[128];
    uint8_t rbuf[128];

    memset(dirname,0x00,sizeof(dirname));
    strncpy(dirname,_current_dir,sizeof(dirname));

    str = parameter;
    parameter = strchr(str,' ');
    parameter++;
    ptname = parameter;

    str = parameter;
    parameter = strchr(str,' ');
    parameter++;
    length = fc_atoi(parameter);

    snprintf(dirname, sizeof(dirname), "%s/%s", _current_dir,ptname);

    FRESULT res;
    FIL file;
    res = f_open(&file,dirname,FA_READ);
    if(res == FR_OK)
    {
        // uint32_t rlen = 0;
        // res = f_read(&file,rbuf,length,&rlen);
        // if(res == FR_OK)
        // {
        //     rbuf[rlen] = 0;
        //     mshell_printf("%s\r\n",rbuf);
        // }
        // else
        // {
        //     mshell_printf("read %s error:%d\r\n",ptname,res);
        // }

        uint32_t flen = f_size(&file);
        uint32_t len = (length>flen)?(flen):(length);
        uint32_t rlen = 0;
        uint32_t num = len/128;
        uint32_t remain = len%128;
        if(remain>0)
            num++;
        for(int i = 0; i < num; i++)
        {
            res = f_read(&file,rbuf,length,&rlen);
            if(res == FR_OK)
            {
                rbuf[rlen] = 0;
                mshell_printf("%s\r\n",rbuf);
            }
        }
        f_close(&file);
    }
    else
    {
        mshell_printf("open %s error:%d\r\n",ptname,res);
    }
}

static void _df(char *str)
{
    mshell_printf("\r\n");

    FRESULT res;
    FATFS *fs;
    DWORD fre_clust, fre_sect, tot_sect;

    /* Get volume information and free clusters of drive 1 */
    res = f_getfree("0:", &fre_clust, &fs);
    if(res)
    {
        mshell_printf("df error:%d\r\n",res);
    }

    /* Get total sectors and free sectors */
    tot_sect = (fs->n_fatent - 2) * fs->csize;
    fre_sect = fre_clust * fs->csize;

    /* Print the free space (assuming 512 bytes/sector) */
    // mshell_printf("df: %10lu / %10lu \r\n", fre_sect / 2, tot_sect / 2);
    mshell_printf("df: %d KiB/ %d KiB\r\n", fre_sect / 2, tot_sect / 2);
}

static void _mkfs(char *str)
{
    mshell_printf("\r\n");
    f_mkfs("0:",1,4096);
    strncpy(_current_dir,"0:",sizeof(_current_dir));
}

static void _ymodem(char *str)
{
    mshell_printf("\r\n");
    SERIAL_t console = (SERIAL_t)mshell_dev();

    char *fname = NULL;
    char mode = 0;
    YMODEM_FS_FILE yfile;

    memset(&yfile,0x00,sizeof(YMODEM_FS_FILE));

    char *parameter = str;
    str = parameter;
    parameter = strchr(str,'-');
    parameter++;
    mode = *parameter;

    if(mode == 'w')
    {
        snprintf(yfile.path,sizeof(yfile.path),"%s/",_current_dir);
        mshell_printf("ymodem -w %s\r\n",yfile.path);

        int ret = ymodem_receive_fs(console,&yfile);
        mshell_printf("ret = %d\r\n",ret);
    }
    else if(mode == 'r')
    {
        str = parameter;
        parameter = strchr(str,' ');
        parameter++;
        fname = parameter;

        FRESULT res;
        FILINFO fno;

        snprintf(yfile.path,sizeof(yfile.path),"%s/%s",_current_dir,fname);
        res = f_stat(yfile.path, &fno);
        if(res != FR_OK)
        {
            mshell_printf("file error");
            return;
        }
        yfile.length = fno.fsize;
        mshell_printf("ymodem -r %s %d\r\n",yfile.path,yfile.length);
        int ret = ymodem_transmit_fs(console,&yfile);
        mshell_printf("ret = %d\r\n",ret);
    }
}

static shell_table _mdsh_table[] =
{
    {"ls",      _list,      NULL},
    {"mkdir",   _mkdir,     NULL},
    {"rm",      _rm,        NULL},
    {"pwd",     _pwd,       NULL},
    {"cd",      _cd,        NULL},
    {"cat",     _cat,       NULL},
    {"df",      _df,        NULL},
    {"mkfs",    _mkfs,      NULL},
    {"ymodem",  _ymodem,    "\r\nymodem -r [filename]\r\nymodem -w\r\n"},
};

static void _mdsh_fs_init(void)
{
    // mshell_printf("%s start\r\n",__FUNCTION__);
    strncpy(_current_dir,"0:",sizeof(_current_dir));
    mdsh_put(_mdsh_table, sizeof(_mdsh_table)/sizeof(shell_table));
}
MDSH_CMD_INIT(_mdsh_fs_init);

